package cn.lg.soar.common.util.reflect;

import java.lang.reflect.*;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @Author: luguoxiang
 * @Date: 2021-06-01 14:26
 * @Description: 反射工具
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface ReflectUtil {

    /**
     * 获取属性值
     * @param object 实例对象
     * @param field 字段
     * @return
     */
    static Object get(Object object, Field field) {
        field.setAccessible(true);
        try {
            object = field.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            field.setAccessible(false);
        }
        return object;
    }

    /**
     * 获取属性值（为null会有空指针异常）
     * @param object 实例对象
     * @param fieldName 字段名称
     * @return
     */
    static Object get(Object object, String fieldName) {
        try {
            return FieldUtils.getValue(object, fieldName);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取属性值
     * @param object 实例对象
     * @param field 字段
     * @return
     * @throws IllegalAccessException
     */
    static Object getThrows(Object object, Field field) throws IllegalAccessException {
        field.setAccessible(true);
        object = field.get(object);
        field.setAccessible(false);
        return object;
    }

    /**
     * 获取值
     * @param object 实例对象
     * @param fieldName 字段名称
     * @return
     * @throws IllegalAccessException
     */
    static Object getThrows(Object object, String fieldName) throws IllegalAccessException {
        return FieldUtils.getValue(object, fieldName);
    }

    /**
     * 设置值
     * @param object 实例对象
     * @param field 字段
     * @param value 值
     */
    static void set(Object object, Field field, Object value) {
        field.setAccessible(true);
        try {
            field.set(object, value);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            field.setAccessible(false);
        }
    }

    /**
     * 设置值
     * @param object 实例对象
     * @param fieldName 字段名
     * @param value 值
     */
    static void set(Object object, String fieldName, Object value) {
        try {
            FieldUtils.setValue(object, fieldName, value);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置值
     * @param object 实例对象
     * @param field 字段
     * @param value 值
     * @throws IllegalAccessException
     */
    static void setThrows(Object o, Field field, Object value) throws IllegalAccessException {
        field.setAccessible(true);
        field.set(o, value);
        field.setAccessible(false);
    }

    /**
     * 设置值
     * @param object 实例对象
     * @param fieldName 字段名
     * @param value 值
     * @throws IllegalAccessException
     */
    static void setThrows(Object object, String fieldName, Object value) throws IllegalAccessException {
        FieldUtils.setValue(object, fieldName, value);
    }

    /**
     * 获取字段
     * @param clazz
     * @param fieldName
     * @return
     */
    static Field getField(Class<?> clazz, String fieldName) {
        return FieldUtils.getField(clazz, fieldName);
    }

    /**
     * 扫描所有字段
     * @param clazz 类类型
     * @param consumer 处理方法
     * @param predicate 停止扫描的类（默认Object）
     */
    static void scanAllField(Class<?> clazz, Consumer<Field> consumer, Predicate<Class<?>> predicate) {
        FieldUtils.scanAllField(clazz, consumer, predicate);
    }

    /**
     * 扫描所有字段
     * @param clazz 类类型
     * @param consumer 处理方法
     */
    static void scanAllField(Class<?> clazz, Consumer<Field> consumer) {
        FieldUtils.scanAllField(clazz, consumer, c -> !Object.class.equals(c));
    }

    /**
     * 扫描类属性(非公有，非静态)
     * @param clazz 类类型
     * @param consumer 属性处理
     * @param predicate  停止扫描的类（默认Object）
     */
    static void scanField(Class<?> clazz, Consumer<Field> consumer, Predicate<Class<?>> predicate) {
        FieldUtils.scan(clazz, consumer, predicate);
    }

    /**
     * 扫描类属性(非公有，非静态)
     * @param clazz 类类型
     * @param consumer 属性处理
     */
    static void scanField(Class<?> clazz, Consumer<Field> consumer) {
        FieldUtils.scan(clazz, consumer, c -> !Object.class.equals(c));
    }

    /**
     * 扫描所有方法
     * @param clazz 类类型
     * @param consumer 处理方法
     * @param predicate 停止扫描的类（默认Object）
     */
    static void scanAllMethod(Class<?> clazz, Consumer<Method> consumer, Predicate<Class<?>> predicate) {
        MethodUtils.scanAllMethod(clazz, consumer, predicate);
    }

    /**
     * 扫描所有方法
     * @param clazz 类类型
     * @param consumer 处理方法
     */
    static void scanAllMethod(Class<?> clazz, Consumer<Method> consumer) {
        MethodUtils.scanAllMethod(clazz, consumer, c -> !Object.class.equals(c));
    }

    /**
     * 扫描非静态方法
     * @param clazz 类类型
     * @param consumer 处理方法
     * @param predicate 停止扫描的类（默认Object）
     */
    static void scanMethod(Class<?> clazz, Consumer<Method> consumer, Predicate<Class<?>> predicate) {
        MethodUtils.scan(clazz, consumer, predicate);
    }

    /**
     * 扫描非静态方法
     * @param clazz 类类型
     * @param consumer 处理方法
     */
    static void scanMethod(Class<?> clazz, Consumer<Method> consumer) {
        MethodUtils.scan(clazz, consumer, c -> !Object.class.equals(c));
    }

    /**
     * 调用方法
     * @param o 实例对象
     * @param method 方法
     * @param params 参数
     * @return
     */
    static Object invoke(Object o, Method method, Object...params) {
        return MethodUtils.invoke(o, method, params);
    }

    /**
     * 调用方法
     * @param o 实例对象
     * @param methodName 方法名
     * @param params 参数
     * @return
     */
    static Object invoke(Object o, String methodName, Object...params) {
        return MethodUtils.invoke(o, methodName, params);
    }

    /**
     * 实例化（调用无参构造器）
     * @param clazz 类类型
     * @param <T>
     * @return
     */
    static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 实例化（调用无参构造器）
     * @param className 类全名
     * @return
     */
    static Object newInstance(String className) {
        Class<?> clazz;
        try {
            clazz = Class.forName(className);
            return clazz.newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 实例化（调用对应的有参构造函数）
     * @param clazz 类类型
     * @param params 参数
     * @param <T>
     * @return
     */
    static <T> T newInstance(Class<T> clazz, Object ...params) {
        return MethodUtils.constructor(clazz, params);
    }

    /**
     * 实例化（调用对应的有参构造函数）
     * @param className 类全名
     * @param params 参数
     * @param <T>
     * @return
     */
    static Object newInstance(String className, Object ...params) {
        try {
            return MethodUtils.constructor(
                    Class.forName(className),
                    params
            );
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建一个数组
     * @param tClass
     * @param length
     * @param <T>
     * @return
     */
    static <T>T[] newArray(Class<T> tClass, int length) {
        return (T[]) Array.newInstance(tClass, length);
    }

    /**
     * 创建一个数组
     * @param className
     * @param length
     * @return
     */
    static Object[] newArray(String className, int length) {
        Class<?> aClass;
        try {
            aClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return newArray(aClass, length);
    }

    /**
     * 扫描指定包下所有类
     * @param packages 报名
     * @param consumer 处理函数
     */
    static void scanClass(String packages, Consumer<Class<?>> consumer) {
        ClassUtils.scan(packages, consumer);
    }

    /**
     * 是否 public 修饰的
     * @param member 成员实例
     * @return
     */
    static boolean isPublic(Member member) {
        return Modifier.isPublic(member.getModifiers());
    }

    /**
     * 是否 static 修饰的
     * @param member 成员实例
     * @return
     */
    static boolean isStatic(Member member) {
        if (member == null) {
            return false;
        }
        return Modifier.isStatic(member.getModifiers());
    }

    /**
     * 是否 static 修饰的
     * @param clazz 类类型
     * @return
     */
    static boolean isStatic(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }
        return Modifier.isStatic(clazz.getModifiers());
    }

    /**
     * 是否 static 修饰的
     * @param instance 实例
     * @return
     */
    static boolean isStatic(Object instance) {
        if (instance == null) {
            return false;
        }
        return Modifier.isStatic(instance.getClass().getModifiers());
    }

    /**
     * 是否 final 修饰的
     * @param member 成员实例
     * @return
     */
    static boolean isFinal(Member member) {
        return Modifier.isFinal(member.getModifiers());
    }

    /**
     * 是否 static 修饰的
     * @param clazz 类类型
     * @return
     */
    static boolean isFinal(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }
        return Modifier.isFinal(clazz.getModifiers());
    }

    /**
     * 是否 static 修饰的
     * @param instance 实例
     * @return
     */
    static boolean isFinal(Object instance) {
        if (instance == null) {
            return false;
        }
        return Modifier.isFinal(instance.getClass().getModifiers());
    }

    /**
     * 是否是接口
     * @param clazz 类类型
     * @return
     */
    static boolean isInterface(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }
        return clazz.isInterface();
    }

    /**
     * 是否是接口
     * @param instance 实例
     * @return
     */
    static boolean isInterface(Object instance) {
        if (instance == null) {
            return false;
        }
        return instance.getClass().isInterface();
    }

}
